package com.eelye.util.http.impl;

import com.eelye.util.http.EasyHttpClient;
import com.eelye.util.http.enums.RequestMethodEnum;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.NotImplementedException;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.HttpClient;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.client.methods.RequestBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import java.io.IOException;
import java.io.InputStream;
import java.nio.charset.Charset;
import java.nio.charset.UnsupportedCharsetException;
import java.util.Map;

@Slf4j
public class ApacheHttpClient implements EasyHttpClient {

    public static final int CONNECT_TIME_OUT = 1000;
    public static final int REQUEST_TIME_OUT = 1000;
    public static final int GET_CONNECTION_TIME_OUT = 1000;//The timeout in milliseconds used when requesting a connection from the connection manager.
    public static final int RESP_LEN = 1024 * 1024;//http响应的大小，超过这个大小不处理

    HttpClient m_client;

    RequestConfig m_defaultConf;

    public ApacheHttpClient() {
        m_client = buildHttpClient();
        m_defaultConf = createConfig();
    }

    @Override
    public void setProxy(String ip, int port) {
        //todo
    }

    @Override
    public <T> T request(RequestMethodEnum method, String uri, String body, Map<String, String> headers, Class<T> t)
            throws IOException {
        //创建request
        RequestBuilder requestBuilder = RequestBuilder.create(method.getCode())
                .setUri(uri);
        if (RequestMethodEnum.Post == method) {
            requestBuilder.setEntity(new StringEntity(body));
        }
        if (null != headers) {
            for (Map.Entry<String, String> e : headers.entrySet()) {
                requestBuilder.setHeader(e.getKey(), e.getValue());
            }
        }
        HttpUriRequest req = requestBuilder.build();

        //发起请求
        HttpResponse resp = m_client.execute(req);
        if (resp.getStatusLine().getStatusCode() == 302L) {
            log.info(resp.getHeaders("Location")[0].getValue());
        }

        //解析返回值
        if (String.class.equals(t)) {
            return (T) getStringResponse(resp);
        }

        return (T) resp;
    }

    @Override
    public void close() {
        throw new NotImplementedException();
    }

    private String getStringResponse(HttpResponse resp) throws IOException {
        byte[] buf = new byte[RESP_LEN];//分配1M空间。

        int contentLen = (int) resp.getEntity().getContentLength();
        if (contentLen < 0) {
            contentLen = RESP_LEN;
        }
        int bufLen = 0;
        InputStream respContent = resp.getEntity().getContent();
        while (contentLen > 0) {
            int readLen = respContent.read(buf, bufLen, buf.length - bufLen);
            if (readLen <= 0) {
                break;
            }
            bufLen += readLen;
        }

        String charsetName = "UTF-8";
        Charset charset = null;
        Header objContentType = resp.getEntity().getContentType();
        if (null != objContentType) {
            String contentType = objContentType.getValue();
            String charsetKey = "charset=";
            int charsetPos = contentType.indexOf(charsetKey);
            if (-1 != charsetPos) {
                charsetName = contentType.substring(contentType.indexOf(charsetKey) + charsetKey.length());
            }
        }
        try {
            charset = Charset.forName(charsetName);
        } catch (UnsupportedCharsetException e) {
            charset = Charset.defaultCharset();
        }

        int len = bufLen;
        if (null != resp.getEntity() && -1 != resp.getEntity().getContentLength()) {
            len = (int) resp.getEntity().getContentLength();
        }

        String ret = new String(buf, 0, len, charset);

        return ret;
    }

    private HttpClient buildHttpClient() {
        CloseableHttpClient client = HttpClients.createDefault();
        return client;
    }

    private RequestConfig createConfig() {
        RequestConfig reqConf = RequestConfig.custom().setSocketTimeout(REQUEST_TIME_OUT)
                .setConnectTimeout(CONNECT_TIME_OUT)
                .setConnectionRequestTimeout(GET_CONNECTION_TIME_OUT)//如果有连接池，从连接池里获取连接的时间
                .build();

        return reqConf;
    }
}
